package com.xxmw.transaction.controller.app;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xxmw.transaction.common.annotation.LoginUser;
import com.xxmw.transaction.common.entity.R;
import com.xxmw.transaction.common.excep.service.TransactionException;
import com.xxmw.transaction.common.utils.Assert;
import com.xxmw.transaction.common.utils.bourse.*;
import com.xxmw.transaction.enumeration.TradeTypeEnum;
import com.xxmw.transaction.model.app.*;
import com.xxmw.transaction.model.brick.Brick;
import com.xxmw.transaction.model.brick.BrickOrder;
import com.xxmw.transaction.model.subscribe.SymbolSub;
import com.xxmw.transaction.service.app.*;
import com.xxmw.transaction.vo.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author luowenliang
 * @since 2020/5/14 14:17
 */
@Slf4j
@RestController
@RequestMapping("/app/brick")
@Api(tags = "搬砖相关接口")
@Service
public class UserBrickController {

    @Autowired
    private SymbolSubService symbolSubService;

    @Autowired
    private SymbolService symbolService;

    @Autowired
    private BourseApiService bourseApiService;

    @Autowired
    private BrickService brickService;

    @Autowired
    private UserBrickService userBrickService;

    @Autowired
    private BrickOrderService brickOrderService;

    @Autowired
    private UserService userService;

    @Autowired
    private UserBrickApiService userBrickApiService;

    /**
     * 可搬砖交易对列表
     * @return
     */
    @GetMapping("/symbolList")
    @ApiOperation("获取可以搬砖的交易对列表")
    public R symbolList () {
        // 返回app端交易对信息列表
        List<SymbolInfoVo> infoVos = new ArrayList<>();

        // 获取可以搬砖的交易对列表
        List<BrickableSymbol> symbolList = symbolSubService.getBrickableSymbol();

        // 获取交易对列表
        List<Symbol> symbols = symbolService.list();
        HashMap<String, Symbol> sbMap = symbols.parallelStream().collect(HashMap::new, (hashMap, symbol) -> hashMap.put(symbol.getName(), symbol), Map::putAll);
        if (null != symbolList && symbolList.size() > 0) {
            symbolList.forEach(item -> {
                SymbolInfoVo symbolInfoVo = new SymbolInfoVo();
                List<SymbolSub> subList = symbolSubService.getBySymbol(item.getSymbol());
                Symbol symbol = sbMap.get(item.getSymbol());
                symbolInfoVo.setName(symbol.getBaseCurrency().toUpperCase() + "/" + symbol.getQuoteCurrency().toUpperCase());
                symbolInfoVo.setBourseList(subList.parallelStream().map(SymbolSub::getBourse).collect(Collectors.toList()));

                infoVos.add(symbolInfoVo);
            });
        }

        return R.ok(infoVos);
    }

    /**
     * 根据交易对获取 可搬砖交易所和该交易对的搬砖策略
     * @param symbol
     * @return
     */
    @GetMapping("/getBySymbol")
    @ApiOperation("获取单个交易对的搬砖策略")
    public R getBySymbol (@ApiIgnore @LoginUser User user,
                          @NotBlank(message = "交易对不能为空") @RequestParam(value = "symbol") String symbol) {
        symbol = symbol.toLowerCase().replace("/", "");
        List<BourseAccountVo> accountVos = new ArrayList<>();

        //查询可搬砖交易所
        List<SymbolSub> subList = symbolSubService.getBySymbol(symbol);
        Symbol sb = symbolService.getBuyName(symbol);
        if (null != subList && subList.size() > 0) {
            subList.forEach(item -> {
                BourseAccountVo bourseAccountVo = new BourseAccountVo();
                bourseAccountVo.setBourse(item.getBourse());
                //绑定了交易所API的需要查询用户余额
                List<BourseApi> apis = bourseApiService.getUserApi(user.getUsername(), item.getBourse());
                if (null != apis && apis.size() > 0) {
                    // accountVo.setAccountName(api.getRemark());
                    bourseAccountVo.setHasAuthorization(true);
                    List<AccountVo> vos = bourseAccountVo.getAccountVos();
                    // accountVo.setBalance(getBalance(api, sb.getBaseCurrency(), sb.getQuoteCurrency()));
                    for (BourseApi api : apis) {
                        AccountVo accountVo = new AccountVo(sb.getBaseCurrency(), sb.getQuoteCurrency());
                        accountVo.setAccountId(api.getId());
                        accountVo.setAccountName(api.getRemark());
                        Map<String, BalanceVo> balance = getBalance(api, sb.getBaseCurrency(), sb.getQuoteCurrency());

                        if (Assert.isNullOrEmpty(balance.get(sb.getBaseCurrency()))) {
                            balance.put(sb.getBaseCurrency(), new BalanceVo());
                        }
                        if (Assert.isNullOrEmpty(balance.get(sb.getQuoteCurrency()))) {
                            balance.put(sb.getQuoteCurrency(), new BalanceVo());
                        }
                        accountVo.setBalance(balance);
                        vos.add(accountVo);
                    }
                }
                accountVos.add(bourseAccountVo);
            });
        }

        //查询该币种可以搬砖策略
        List<Brick> brickList = brickService.getAvailableSymbol(symbol);
        if (null != brickList && brickList.size() > 0) {
            brickList.forEach(item -> {
                Symbol name = symbolService.getBuyName(item.getSymbol());
                item.setSymbol(name.getBaseCurrency().toUpperCase() + "/" + name.getQuoteCurrency().toUpperCase());
            });
        }

        return R.ok().put("info", accountVos).put("brickList", brickList);
    }

    /**
     * 获取帐户余额
     * @param api
     * @param baseCurrency
     * @param quoteCurrency
     * @return
     */
    private Map<String, BalanceVo> getBalance (BourseApi api, String baseCurrency, String quoteCurrency) {
        Map<String, BalanceVo> map = new HashMap<>(16);
        final List<String> currencys = Arrays.asList(baseCurrency, quoteCurrency);
        try{
            switch (api.getBourse()) {
                case 1:
                    //币查询余额
                    map = HuobiUtil.getBalance(api, currencys);
                    break;
                case 2:
                    //币安查询
                    map = BinanceUtil.getBalance(api, currencys);
                    break;
                case 3:
                    map = OkexUtil.getBalance(api, currencys);
                    break;
                case 4:
                    map = BitforexUtil.getBalance(api, currencys);
                    break;
                case 5:
                    map = ZBUtil.getBalance(api, currencys);
                    break;
                case 6:
                    map = PoloniexUtil.getBalance(api, currencys);
                    break;
                case 7:
                    map = JiuBiUtil.getBalance(api, currencys);
                    break;
                case 8:
                    map = BikiUtil.getBalance(api, currencys);
                    break;
                default:
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return map;
    }

    /**
     * 用户新增搬砖
     * @param brickId 搬砖策略ID
     * @param bourses 交易所多个以逗号隔开 1,2,3
     * @return
     */
    @PostMapping("/add")
    @ApiOperation("新增搬砖策略")
    public R add (@ApiIgnore @LoginUser User user,
                  @NotBlank(message = "名称不能为空") @RequestParam(value = "name") String name,
                  @NotBlank(message = "请选择搬砖策略") @RequestParam(value = "brickId") Integer brickId,
                  @NotBlank(message = "请选择交易所") @RequestParam(value = "bourses") String bourses) {
        if (!userService.isVip(user.getUsername())) {
            return R.error("开通vip后方可操作");
        }
        UserBrick userBrick = new UserBrick();

        Brick brick = brickService.getById(brickId);

        if (null == brick || brick.getStatus().equals(Brick.Status.CLOSE.value())) {
            return R.error("该策略不存在");
        }
        userBrick.setStatus(2);
        userBrick.setBrickId(brickId);
        userBrick.setUserId(user.getId());
        userBrick.setName(name);
        // 获取绑定的交易所列表
        String bourse = getBourse(user.getUsername(), bourses);
        userBrick.setBourseIds(bourse);

        userBrick.setSymbol(brick.getSymbol());
        try {
            userBrickService.saveOrUpdate(userBrick, bourses, user.getUsername());
        } catch (DuplicateKeyException e) {
            return R.error("策略重复");
        }
        return R.ok();
    }

    /**
     * 获取用户已有的搬砖策略
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("获取已有的搬砖策略")
    public R list (@ApiIgnore @LoginUser User user, @RequestParam(value = "symbol") String symbol) {
        symbol = symbol.toLowerCase().replace("/", "");
        List<UserBrickDetailVo> userBrickList = userBrickService.findByUserId(user.getId(), symbol);
        for (UserBrickDetailVo userBrickDetailVo:
        userBrickList) {
            userBrickDetailVo.setUserBrickApiVos(userBrickApiService.listByUserBrick(userBrickDetailVo.getId()));
        }
        return R.ok(userBrickList);
    }

    /**
     * 获取用户搬砖详情
     * @return
     */
    @GetMapping("/detail")
    @ApiOperation("获取搬砖详情")
    @Deprecated
    public R detail (@ApiIgnore @LoginUser User user,
                   @NotBlank(message = "用户搬砖ID不能为空") @RequestParam(value = "userBrickId") String userBrickId) {
        UserBrick userBrick = userBrickService.getById(userBrickId);

        if (null == userBrick) {
            return R.error("未获取到用户搬砖");
        }

        UserBrickDetailVo detailVo = new UserBrickDetailVo();
        Brick brick = brickService.getById(userBrick.getBrickId());
        detailVo.setUserBrickName(userBrick.getName());
        detailVo.setBrickName(brick.getTitle());
        detailVo.setDescription(brick.getDescription());

        return R.ok(detailVo);
    }


    /**
     * 获取用户搬砖订单
     * 搬砖订单两单为一笔记录，需计算利润
     * @return
     */
    @GetMapping("/orderList")
    @ApiOperation("获取用户板砖订单列表")
    public R orderList (@ApiIgnore @LoginUser User user,
                        @RequestParam Long brickId,
                        @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
                        @RequestParam(value = "pageSize", defaultValue = "20")Integer pageSize) {
        //P<BrickOrder> pageList = brickOrderService.pageList(pageNum, pageSize, null, null, 6, null, user.getUsername(),brickId);
        UserBrick userBrick = userBrickService.getById(brickId);
        if (Assert.isNullOrEmpty(userBrick)) {
            return R.error("策略不存在");
        }
        Page<BrickOrderVo> brickOrderVoIPage = brickOrderService.pageListByUserAndBrickId(new Page<>(pageNum, pageSize), user.getUsername(), brickId);
        return R.ok(brickOrderVoIPage);
    }


    /**
     * 将错误订单中未成交的订单撤回
     * @param orderNo
     * @return
     */
    @PostMapping("orderReject")
    @ApiOperation("将错误订单中未成交的订单撤回")
    public R orderReject (@ApiIgnore @LoginUser User user,@RequestParam Long orderNo) {
        LambdaQueryWrapper<BrickOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BrickOrder::getOutId, orderNo);
        wrapper.eq(BrickOrder::getUsername, user.getUsername());
        BrickOrder order = brickOrderService.getOne(wrapper);
        if (Assert.isNullOrEmpty(order)) {
            return R.error("订单不存在");
        }
        brickOrderService.cancelOrder(order);
        return R.ok();
    }

    /**
     * 将错误订单中成交的订单对冲
     * @param orderNo
     * @return
     */
    @PostMapping("orderHedging")
    @ApiOperation("将错误订单中成交的订单对冲")
    public R orderHedging (@ApiIgnore @LoginUser User user,@RequestParam Long orderNo) {
        brickOrderService.orderHedging(user.getUsername(),  orderNo);
        return R.ok();
    }




    /**
     * 开启或者关闭策略
     * @param user
     * @param id 策略id
     * @param status 状态
     * @return
     */
    @PostMapping("openeOrClose")
    @ApiOperation(value = "开启/关闭策略",notes = "同一个币种的策略只能够开启一个  status： 1=关闭  2 = 开启")
    public R openOrClose (@ApiIgnore @LoginUser User user, @RequestParam Integer id ,@RequestParam Integer status) {
        if(!status.equals(1) && !status.equals(2)) {
            return R.error();
        }
        if (status.equals(2)) {
            if (!userService.isVip(user.getUsername())) {
                return R.error("开通vip后方可操作");
            }
        }
        UserBrick userBrick = userBrickService.getById(id);
        if (Assert.isNullOrEmpty(userBrick) || !userBrick.getUserId().equals(user.getId())) {
            return R.error();
        }
        userBrickService.updateStatus(user.getId(), id, status);
        return R.ok();
    }

    /**
     * 修改策略，策略修改后将会打开
     * @param userBrick
     * @return
     */
    @PostMapping("update")
    @ApiOperation("修改策略，策略修改后将会关闭")
    public R update (@ApiIgnore @LoginUser User user, UserBrick userBrick) {
        if (!userService.isVip(user.getUsername())) {
            return R.error("开通vip后方可操作");
        }
        String apiString = userBrick.getBourseIds();
        userBrick.setStatus(2);
        if (userBrick.getBourseIds() != null) {
//            String[] bourseArray = userBrick.getBourseIds().split(",");
//            if (bourseArray.length <= 1) {
//                return R.error("至少选择两个交易所才可进行搬砖");
//            }

            // 获取绑定的交易所列表
            String bourse = getBourse(user.getUsername(), userBrick.getBourseIds());
            userBrick.setBourseIds(bourse);
        }
        try {
            userBrickService.saveOrUpdate(userBrick, apiString, user.getUsername());
        } catch (DuplicateKeyException e) {
            return R.error("策略重复");
        }

        return R.ok();
    }

    /**
     * 统计用户搬砖收益
     * @return
     */
    @GetMapping("/earnings")
    @ApiOperation("统计用户搬砖收益")
    public R earnings (@ApiIgnore @LoginUser User user) {
        Map<String, Map<String, String>> map = new HashMap<>(16);

        Calendar cal = Calendar.getInstance();
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        Date todayZero = cal.getTime();
        Date yesterdayZero = new Date(todayZero.getTime() -(24*60*60*1000));

        //昨日收益
        Map<String, String> yesterdayProfit = brickOrderService.userTotalProfit(user.getUsername(), yesterdayZero, todayZero);
        Map<String, String> totalProfit = brickOrderService.userTotalProfit(user.getUsername(), null, null);

        map.put("yesterdayProfit", yesterdayProfit);
        map.put("totalProfit", totalProfit);

        return R.ok(map);
    }

    /**
     * 获取用户绑定的api的交易所列表
     * @param username
     * @param apiString
     * @return
     */
    private String getBourse(String username, String apiString) {
        String[] apis = apiString.split(",");
        ArrayList<Integer> apiList = new ArrayList<>();
        for (String api:
             apis) {
            apiList.add(Integer.valueOf(api));
        }
        List<BourseApi> bourseList = bourseApiService.getBourseByApi(username, apiList);
        if (Assert.isNullOrEmpty(bourseList) || bourseList.size() < 2) {
            throw new TransactionException("至少选择两个交易所才可进行搬砖");
        }
        StringBuilder bourses = new StringBuilder();
        for (BourseApi bourse:
                bourseList) {
            bourses.append(bourse.getBourse()).append(",");
        }
        return bourses.toString().substring(0, bourses.length() -1);
    }
}
